package com.apexsoft.front.common.utils.session.impl;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.StreamCorruptedException;
import java.util.Set;
import java.util.TreeSet;

import javax.servlet.http.HttpServletRequest;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.core.Logger;

import com.apexsoft.front.common.config.CommonConfig;
import com.apexsoft.front.common.utils.LogUtil;
import com.apexsoft.front.common.utils.session.Cache;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * redis实现
 * @author dinglei
 *
 */
public class RedisImpl extends Cache {

	private static final Logger log = (Logger) LogManager.getRootLogger();
	
	private static JedisPool jedisPool = null;
	
	private String sessionId = null;
	
	public static void initJedisPool(JedisPool jedisPool){
		RedisImpl.jedisPool = jedisPool;
	}
	
	//-----------------------------------------------------------------------------------------
	
	public RedisImpl(HttpServletRequest request){
		if(request!=null)
			this.sessionId = request.getSession().getId();
		else
			this.sessionId = "";
	}
	
	public RedisImpl(String sessionId){
		this.sessionId = sessionId;
	}

	@Override
	public Object get(String key) {
		key = sessionId + key;
		return this.getCache(key);
	}

	/**
	 * 会话相关，并且设定会话过期时间 
	 */
	@Override
	public boolean set(String key, Object value, int second) {
		key = sessionId + key;
		return this.setRedisData(key, value, second);
	}

	/**
	 * 会话从新计时
	 */
	@Override
	public boolean expire(String key) {
		boolean ret = false;
		key = sessionId + key;
		Jedis jedis = jedisPool.getResource();
		try{
			if(jedis.get(key.getBytes())!=null) {
				int REDIS_SESSION_TIMEOUT = 60 * CommonConfig.getInt("REDIS.SESSION.TIMEOUT");
				Long jedisResult = jedis.expire(key.getBytes(), REDIS_SESSION_TIMEOUT);
				if (jedisResult == 1)
					return true;
			 }
		}
		catch(Exception e){
			LogUtil.exceptionLog(log, e);
		}
		finally{
			jedisPool.returnResource(jedis);
		}
		return ret;
	}
	
	/**
	 * 获取剩余的生产时间 单位秒
	 * @param key
	 * @return
	 */
	@Override
	public long getTTL(String key) {
		Jedis jedis = jedisPool.getResource();
		long ttl = jedis.ttl(key);
		jedisPool.returnResource(jedis);
		return ttl;
	}

	@Override
	public void remove(String key) {
		key = sessionId + key;
		this.removeCache(key);
	}
	
	//------------------------------------------------------------------------------------
	
	/**
	 * 会话无关，并且不超时
	 */
	@Override
	public boolean setCache(String key, Object value){
		return this.setRedisData(key, value, 0);
	}
	
	@Override
	public boolean setCache(String key,Object value,int second){
		return this.setRedisData(key, value, second);
	}

	@Override
	public Object getCache(String key) {
		Jedis jedis = jedisPool.getResource();
		
		ByteArrayInputStream bais = null;
		ObjectInputStream ois = null;
		
		try{
			byte[] value = null;
			if(jedis!=null)
				value = jedis.get(key.getBytes("UTF-8"));
			
			if(value!=null){
				try{
					bais = new ByteArrayInputStream(value);
					ois = new ObjectInputStream(bais);
					return ois.readObject();
				}
				catch(StreamCorruptedException sce){
					return new String(value);
				}
			}
		}
		catch(Exception e){
			LogUtil.exceptionLog(log, e);
		}
		finally{
			jedisPool.returnResource(jedis);
			try{
				if(ois!=null){
					ois.close();
				}
				if(bais!=null){
					bais.close();
				}
			}catch(IOException ioe){
				LogUtil.exceptionLog(log, ioe);
			}
		}
		return null;
	}
	
	@Override
	public Object getSetByPattern(String pattern) {
		Jedis jedis = jedisPool.getResource();
		try{
			Set<String> setKeys = null;
			if(jedis!=null)
				setKeys = new TreeSet<String>(jedis.keys(pattern));
			if(setKeys!=null){
				return setKeys;
			}
		}
		catch(Exception e){
			LogUtil.exceptionLog(log, e);
		}
		finally{
			jedisPool.returnResource(jedis);
		}
		return null;
	}
	
	@Override
	public boolean removeCache(String key) {
		boolean ret = false;
		Jedis jedis = jedisPool.getResource();
		try{
			Long jedisResult = jedis.del(key.getBytes());
			if (jedisResult == 1) {
				ret = true;
			}
		}
		catch(Exception e){
			LogUtil.exceptionLog(log, e);
		}
		finally{
			jedisPool.returnResource(jedis);
		}
		return ret;
	}
	
	private boolean setRedisData(String key, Object value, int second) {
		boolean ret = false;
		Jedis jedis = jedisPool.getResource();
		
		ByteArrayOutputStream baos = null;
		ObjectOutputStream oos = null;
		
		try{
			if(value!=null){
				int saveCount = 2;
				String jedisResult = "";
				for (int i = 0; i < saveCount; i++) {
					baos = new ByteArrayOutputStream();
					oos = new ObjectOutputStream(baos);
					oos.writeObject(value);
					oos.flush();
					byte[] bytes = baos.toByteArray();
					jedisResult = jedis.set(key.getBytes(), bytes);
					if (jedisResult.equals("OK")) {
						ret = true;
						break;
					}
				}
				if(second>0) {
					Long jedisExpireResult = jedis.expire(key, second);
					if (jedisExpireResult != 1)
						ret = false;
				}
					
			}
		}
		catch(Exception e){
			LogUtil.exceptionLog(log, e);
		}
		finally{
			jedisPool.returnResource(jedis);
			try{
				if(oos!=null){
					oos.close();
				}
				if(baos!=null){
					baos.close();
				}
			}catch(IOException ioe){
				LogUtil.exceptionLog(log, ioe);
			}
		}
		return ret;
	}

}
